package com.lizbet.server;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;

import org.apache.xerces.jaxp.DocumentBuilderFactoryImpl;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.lbs.core.shared.tables.AbstractData;
import com.lbs.core.shared.tables.LbsKeyValuePair;



public class XmlFact extends XmlRaw{

  NumberFormat numformat = NumberFormat.getNumberInstance();
  protected String mes,ano;  //Se usaron para el reporte mensual al SAT
  AbstractData fact;

/*
 * Crea un objeto xmlFact a partir de la base de datos
 */
  @SuppressWarnings("unchecked")
public XmlFact(AbstractData fact){
    this.fact=fact;
    numformat.setMinimumFractionDigits(2);
    numformat.setMaximumFractionDigits(2);
    numformat.setGroupingUsed(false);

    SimpleDateFormat dformat;
    dformat = (SimpleDateFormat)DateFormat.getDateInstance();
    dformat.setTimeZone(TimeZone.getTimeZone("America/Mexico_City"));
    dformat.applyPattern("yyyy-MM-dd'T'hh:mm:ss");
    SimpleDateFormat mesformat;
    mesformat = (SimpleDateFormat)DateFormat.getDateInstance();
    mesformat.applyPattern("MM");
    SimpleDateFormat anoformat;
    anoformat = (SimpleDateFormat)DateFormat.getDateInstance();
    anoformat.applyPattern("yyyy");

    try {
      DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
      DocumentBuilder docBuilder = dbFactory.newDocumentBuilder();
      xmlDoc = docBuilder.newDocument();
    } catch(Exception e) {
      System.out.println("Error : " + e);
    }
    
    String tipoCfd;
    if (fact.get("empresa.empresaMadre")!=null)
    	tipoCfd=fact.getString("empresa.empresaMadre.tipoCfd.nombre");
    else
    	tipoCfd=fact.getString("empresa.tipoCfd.nombre");
    
    if (tipoCfd.equals("CFDI"))
	    domainPrefix = "cfdi:";
    
 //Elemento Comprobante
    doc = xmlDoc.createElement(domainPrefix + "Comprobante");
    if (tipoCfd.equals("CFDI"))
	    doc.setAttribute("version", "3.2");
    else
        doc.setAttribute("version", "2.2");
    
    
    //Metodo de Pago y cuenta bancaria
    if (fact.get("factPagos")==null || ((List<AbstractData>)fact.get("factPagos")).size()==0 || ((List<AbstractData>)fact.get("factPagos")).get(0).getAbstractData("metodoPago")==null){
    	//Si no hay lista de pagos, verificamos en los datos de la factura
        if (!(fact.get("metodoPago")==null ? "" : fact.getString("metodoPago")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
        	doc.setAttribute("metodoDePago", fact.getString("metodoPago").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
        else
        	doc.setAttribute("metodoDePago", "No identificado");
        //Ahora con el numero de cuenta
        if (!(fact.get("noCuenta")==null ? "" : fact.getString("noCuenta")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty()){
            String cuenta = fact.getString("noCuenta");
            cuenta = cuenta.replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim();
            doc.setAttribute("NumCtaPago", cuenta);
        }
    }else{//Desde la lista de pagos
        doc.setAttribute("metodoDePago", ((AbstractData)((List)fact.get("factPagos")).get(0)).getAbstractData("metodoPago").getString("nombre").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
        if(((AbstractData)((List)fact.get("factPagos")).get(0)).get("noCuenta") != null && !((AbstractData)((List)fact.get("factPagos")).get(0)).getString("noCuenta").isEmpty()){
            String cuenta = ((AbstractData)((List)fact.get("factPagos")).get(0)).getString("noCuenta");
            cuenta = cuenta.replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim();
            doc.setAttribute("NumCtaPago", cuenta);
        }
    }
    //Serie de folio
    if (!(fact.get("serFolio")==null ? "" : fact.getString("serFolio")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
        doc.setAttribute("serie", fact.getString("serFolio").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    doc.setAttribute("folio", fact.getString("numFolio").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    doc.setAttribute("fecha", dformat.format(fact.getDate("fecha")));
    mes = mesformat.format(fact.getDate("fecha"));
    ano = anoformat.format(fact.getDate("fecha"));
    if (!(fact.get("noAprob")==null ? "" : fact.get("noAprob").toString()).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
    	doc.setAttribute("noAprobacion", fact.get("noAprob").toString().replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    if (!(fact.get("anoAprob")==null ? "" : fact.get("anoAprob").toString()).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
    	doc.setAttribute("anoAprobacion", fact.get("anoAprob").toString().replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    
    //Forma de pago, puede ser AbstractData o String
    if (fact.get("formaPago") instanceof AbstractData)
    	doc.setAttribute("formaDePago", fact.getAbstractData("formaPago").getString("nombre").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    if (fact.get("formaDePago")!=null)
    	doc.setAttribute("formaDePago", fact.getString("formaDePago").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    
    if (!(fact.get("condicionesDePago")==null ? "" : fact.get("condicionesDePago").toString()).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
    	doc.setAttribute("condicionesDePago", fact.getString("condicionesDePago").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    if (!(fact.get("noCertificado")==null ? "" : fact.get("noCertificado").toString()).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
    	doc.setAttribute("noCertificado", fact.getString("noCertificado").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    
    //Moneda, puede ser AbstractData o String
    if (fact.get("moneda") instanceof AbstractData)
    	doc.setAttribute("Moneda", fact.getAbstractData("moneda").getString("abrev").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    else
    	doc.setAttribute("Moneda", fact.getString("moneda").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    
    if (fact.get("tc")!=null)
    	doc.setAttribute("TipoCambio", numformat.format(fact.getDouble("tc")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    if (!(fact.get("certificado")==null ? "" : fact.get("certificado").toString()).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
    	doc.setAttribute("certificado", fact.getString("certificado").replace("\n", "").replace("\r", "").replace("\n\r", "").replace("\r\n", ""));
    doc.setAttribute("subTotal", numformat.format(fact.getDouble("subTotal")));
    doc.setAttribute("total", numformat.format(fact.getDouble("total")));
    doc.setAttribute("tipoDeComprobante", fact.getString("tipoComprobante").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    xmlDoc.appendChild(doc);


    //Es una sucursal???
    if (fact.get("empresa.empresaMadre")!=null){
    	crearPartner(fact.getAbstractData("empresa.empresaMadre"),fact.getAbstractData("empresa.empresaMadre.dirFisc"),"Emisor","DomicilioFiscal",fact.getAbstractData("empresa.dirFisc"));
    }else
    	crearPartner(fact.getAbstractData("empresa"),fact.getAbstractData("empresa.dirFisc"),"Emisor","DomicilioFiscal",null);
    
    crearPartner(fact.getAbstractData("partner"),fact.getAbstractData("dirPartner"),"Receptor","Domicilio",null);
    crearConceptos((List<AbstractData>)fact.get("factPart"));
    crearImpuestos(fact);

    complementWithBasicData();
  }

	public XmlFact(byte[] byteArray) throws myXmlParsingException {
		super(byteArray);
	}

public void setSello(String sello){
	    doc.setAttribute("sello", sello.replace("\n", "").replace("\r", "").replace("\n\r", "").replace("\r\n", ""));
  }
  public void setNoCert(String no){
	  doc.setAttribute("noCertificado", no.replace("\n", "").replace("\r", "").replace("\n\r", "").replace("\r\n", ""));
  }
  public void setCert(String cert){
	  doc.setAttribute("certificado", cert.replace("\n", "").replace("\r", "").replace("\n\r", "").replace("\r\n", ""));
  }

  public void crearPartner(AbstractData partner, AbstractData dir, String nodeName, String dirNodeName, AbstractData dirExpedicion) {
      Element elemento;
      Element item;

      elemento = xmlDoc.createElement(domainPrefix + ""+nodeName);
      elemento.setAttribute("rfc", partner.getString("rfc").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      elemento.setAttribute("nombre", partner.getString("nombre").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      if (doc.getElementsByTagName(domainPrefix + "Receptor")!=null)
    	  doc.insertBefore(elemento, doc.getElementsByTagName(domainPrefix + "Receptor").item(0));
      else
    	  doc.appendChild(elemento);
      

      item = xmlDoc.createElement(domainPrefix + ""+dirNodeName);
      item.setAttribute("calle", dir.getString("calle").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      if(!(dir.getString("noExt")==null ? "" : dir.getString("noExt")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
        item.setAttribute("noExterior", dir.getString("noExt").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      if(!(dir.getString("noInt")==null ? "" : dir.getString("noInt")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
        item.setAttribute("noInterior", dir.getString("noInt").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      if(!(dir.getString("colonia")==null ? "" : dir.getString("colonia")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
    	  item.setAttribute("colonia", dir.getString("colonia").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      if(!(dir.getString("referencia")==null ? "" : dir.getString("referencia")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
        item.setAttribute("referencia", dir.getString("referencia").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      item.setAttribute("municipio", dir.getString("munDel").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      item.setAttribute("estado", dir.getString("estado").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      item.setAttribute("pais", dir.getString("pais").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      if(!(dir.get("cp")==null ? "" : dir.getString("cp")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
        item.setAttribute("codigoPostal", dir.getString("cp").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      
      if (dirNodeName.equals("DomicilioFiscal") && dirExpedicion==null)
    	  doc.setAttribute("LugarExpedicion", (item.getAttribute("pais") +", "+item.getAttribute("estado")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      elemento.appendChild(item);
      
      
      //Expedido en...
      if (dirExpedicion!=null){
          item = xmlDoc.createElement(domainPrefix + "ExpedidoEn");
          item.setAttribute("calle", dirExpedicion.getString("calle").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
          if(!(dirExpedicion.getString("noExt")==null ? "" : dirExpedicion.getString("noExt")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
            item.setAttribute("noExterior", dirExpedicion.getString("noExt").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
          if(!(dirExpedicion.getString("noInt")==null ? "" : dirExpedicion.getString("noInt")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
            item.setAttribute("noInterior", dirExpedicion.getString("noInt").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
          if(!(dirExpedicion.getString("colonia")==null ? "" : dirExpedicion.getString("colonia")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
        	  item.setAttribute("colonia", dirExpedicion.getString("colonia").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
          if(!(dirExpedicion.getString("referencia")==null ? "" : dirExpedicion.getString("referencia")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
            item.setAttribute("referencia", dirExpedicion.getString("referencia").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
          item.setAttribute("municipio", dirExpedicion.getString("munDel").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
          item.setAttribute("estado", dirExpedicion.getString("estado").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
          item.setAttribute("pais", dirExpedicion.getString("pais").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
          if(!(dirExpedicion.get("cp")==null ? "" : dirExpedicion.getString("cp")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
            item.setAttribute("codigoPostal", dirExpedicion.getString("cp").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    	  
    	  doc.setAttribute("LugarExpedicion", (item.getAttribute("pais") +", "+item.getAttribute("estado")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
    	  elemento.appendChild(item);
      }
      
      if (nodeName.equals("Emisor"))
    	  crearRegimenes((List)partner.get("regimenes"));
  }
  
  private void crearRegimenes(List<AbstractData> regimenes)
  {
    Element elemento = (Element)this.doc.getElementsByTagName(this.domainPrefix + "Emisor").item(0);

    for (AbstractData regimen : regimenes) {
      Element item = this.xmlDoc.createElement(this.domainPrefix + "RegimenFiscal");
      item.setAttribute("Regimen", regimen.getString("regimen").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
      elemento.appendChild(item);
    }
  }


  private void crearConceptos(List<AbstractData> partidas) {
      Element elemento;
      Element item;
      Element itemCuentaPredial;

      elemento = xmlDoc.createElement(domainPrefix + "Conceptos");
      doc.appendChild(elemento);

      for (AbstractData partida : partidas){
          item = xmlDoc.createElement(domainPrefix + "Concepto");
          item.setAttribute("cantidad", numformat.format(partida.getDouble("cantidad")));
          if(!(partida.get("medida")==null ? "" : partida.getString("medida")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
              item.setAttribute("unidad", partida.getString("medida").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
          if(!(partida.get("codigo")==null ? "" : partida.getString("codigo")).replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim().isEmpty())
            item.setAttribute("noIdentificacion", partida.getString("codigo").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").replaceAll("|", "").trim());
          item.setAttribute("descripcion", partida.getString("desc"));
          item.setAttribute("valorUnitario", numformat.format(partida.getDouble("impUnit")));
          item.setAttribute("importe", numformat.format(partida.getDouble("impTot")));

          if (partida.get("cuentaPredial")!=null && !partida.getString("cuentaPredial").isEmpty()){
        	  itemCuentaPredial = xmlDoc.createElement(domainPrefix + "CuentaPredial");
        	  itemCuentaPredial.setAttribute("numero", partida.getString("cuentaPredial"));
        	  item.appendChild(itemCuentaPredial);
          }
          elemento.appendChild(item);
      }
  }

  @SuppressWarnings("unchecked")
private void crearImpuestos(AbstractData fact) {
	     Element impuestos = xmlDoc.createElement(domainPrefix + "Impuestos");
	     impuestos.setAttribute("totalImpuestosTrasladados", numformat.format(fact.getDouble("iva")));
	 
	     if (fact.get("retIsr") != null) {
	       impuestos.setAttribute("totalImpuestosRetenidos", numformat.format(fact.getDouble("retIsr").doubleValue() + fact.getDouble("retIva").doubleValue()));
	     }
	     doc.appendChild(impuestos);
	 
	     Element item;;
	     AbstractData impTras = new AbstractData();
	 
	     //Se crea una lista de impuestos por tasa
	     for (AbstractData part : (List<AbstractData>)fact.get("factPart")){
	    	 //No puede haber Keys, que contengan punto
	       String tasa = part.getString("tasa").replace(".", "X");
	       if (impTras.get(tasa) == null) {
	         impTras.add(tasa, new Double(0.0D));
	       }
	       Double d = impTras.getDouble(tasa);
	       d = Double.valueOf(d.doubleValue() + part.getDouble("iva").doubleValue());
	       impTras.add(tasa, d);
	     }
	 
	     //Retenciones
	     if (fact.get("retIsr") != null) {
		       item = xmlDoc.createElement(domainPrefix + "Retenciones");
		       impuestos.appendChild(item);
		       Element retencion = xmlDoc.createElement(domainPrefix + "Retencion");
		       retencion.setAttribute("impuesto", "IVA");
		       retencion.setAttribute("importe", numformat.format(fact.getDouble("retIva")));
		       item.appendChild(retencion);
		       retencion = xmlDoc.createElement(domainPrefix + "Retencion");
		       retencion.setAttribute("impuesto", "ISR");
		       retencion.setAttribute("importe", numformat.format(fact.getDouble("retIsr")));
		       item.appendChild(retencion);
		 }
	     
	     
		item = xmlDoc.createElement(domainPrefix + "Traslados");
		impuestos.appendChild(item);
	     //traslados
	     for (LbsKeyValuePair part : impTras.getData()) {
			Element traslado = this.xmlDoc.createElement(domainPrefix + "Traslado");
			traslado.setAttribute("impuesto", "IVA");
			traslado.setAttribute("importe", numformat.format(part.getValue()));
			traslado.setAttribute("tasa", numformat.format(new Double(part.getKey().replace("X", ".")).doubleValue() * 100.0D));
			item.appendChild(traslado);
	     }
	 

  }  
  
  public String getCadenaOriginal(){
	  String result = null;
	  String file;
	  ByteArrayOutputStream cadena = new ByteArrayOutputStream(); 

	  file=doc.getAttribute("version")+".xslt";

	   TransformerFactory tFactory = TransformerFactory.newInstance();
	    try {
	  	  ByteArrayInputStream input = new ByteArrayInputStream(toString().getBytes("UTF8"));
			Transformer transformer =
			  tFactory.newTransformer
			     (new javax.xml.transform.stream.StreamSource
			        (file));
		    transformer.transform
		      (new javax.xml.transform.stream.StreamSource(input),
		       new javax.xml.transform.stream.StreamResult(cadena));
		    result = cadena.toString("UTF8");
		    //Quitamos la etiqueta <?xml....> en caso de existir
		    if (result.startsWith("<?xml"))
		    	result=result.substring(38);
		    
		    //Existia un error al procesar <xsl:output method="text" version="1.0" encoding="UTF-8" indent="no"/>
		    //En el appEngine
		    result=result.replace("&amp;", "&");
		    result=result.replace("&quot;", "\"");
		    result=result.replace("&lt;", "<");
		    result=result.replace("&gt;", ">");
		    result=result.replace("&apos;", "'");
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	    return result;
  }

  public String getCadenaTimbre(){
	  return "||" + getAttrib(domainPrefix + "Complemento/tfd:TimbreFiscalDigital", "version") + "|" +
	  		 getAttrib(domainPrefix + "Complemento/tfd:TimbreFiscalDigital", "UUID") + "|" +
	  		 getAttrib(domainPrefix + "Complemento/tfd:TimbreFiscalDigital", "FechaTimbrado") + "|" +
	  		 getAttrib(domainPrefix + "Complemento/tfd:TimbreFiscalDigital", "selloCFD") + "|" +
	  		 getAttrib(domainPrefix + "Complemento/tfd:TimbreFiscalDigital", "noCertificadoSAT") +"||" ;
  }
  
  public String getMes(){return this.mes;}
  public String getAno(){return this.ano;}


  public Node getAdenda(){
	  if (doc.getElementsByTagName(domainPrefix + "Addenda").item(0)!=null)
		  return doc.removeChild(doc.getElementsByTagName(domainPrefix + "Addenda").item(0));
	  else
		  return null;
  }
  public void setAdenda(Node addenda){
	  if (addenda!=null){
		  Node newNode = xmlDoc.importNode(addenda, true);
		  doc.appendChild(newNode);
	  }
  }
  
  public Node delLbsAddenda(){
	  Node adenda=null;
	  if (doc.getElementsByTagName(domainPrefix + "Addenda").getLength()>0){
		  adenda = doc.getElementsByTagName(domainPrefix + "Addenda").item(0);
		  if(doc.getElementsByTagName("lbs:LizBetSoft").getLength()>0)
			  return adenda.removeChild(doc.getElementsByTagName("lbs:LizBetSoft").item(0));
		  else
			  return null;
	  }else
		  return null;
  }
  
  public void setLbsAdenda(Node addenda){
	  if (doc.getElementsByTagName(domainPrefix + "Addenda").getLength()>0){
		  Node newNode = xmlDoc.importNode(addenda, true);
		  doc.getElementsByTagName(domainPrefix + "Addenda").item(0).appendChild(newNode);
	  }else{
		  addenda = xmlDoc.createElement(domainPrefix + "Addenda");
		  doc.appendChild(addenda);
		  Node newNode = xmlDoc.importNode(addenda, true);
		  addenda.appendChild(newNode);
	  }
  }
    
  
  public void crearAdicionales(List<AbstractData> a) {
      Element elemento;
      Element item;

      elemento = (Element) xmlDoc.getElementsByTagName("lbs:LizBetSoft").item(0);


      for(AbstractData ad : a){
//            System.out.println(ad.getNombreCampo() + ": " + ad.getValor());
      	if (!ad.getString("valor").isEmpty()){
	        item = xmlDoc.createElement("lbs:adic"+ad.getString("nombre"));
		    item.setAttribute("nombre", ad.getString("nombre"));
		    item.setAttribute("valor", ad.getString("valor"));
		    item.setAttribute("todo", ad.getString("nombre")+": "+ad.getString("valor"));
		    elemento.appendChild(item);
    	}
      }
  }

  
  
  public void complementWithBasicData(){
	SimpleDateFormat dformat;
	numformat.setMinimumFractionDigits(2);
	numformat.setMaximumFractionDigits(2);
	numformat.setGroupingUsed(false);
	Element Impuestos;
	dformat = (SimpleDateFormat)DateFormat.getDateInstance();
	dformat.setTimeZone(TimeZone.getTimeZone("America/Mexico_City"));
	dformat.applyPattern("yyyy-MM-dd'T'hh:mm:ss");
	
	if (doc.getAttribute("version")==null || doc.getAttribute("version").isEmpty())
		doc.setAttribute("version", "3.2");
	
	if (doc.getAttribute("version")==null || doc.getAttribute("version").startsWith("3")){
	    doc.setAttribute("xmlns:cfdi", "http://www.sat.gob.mx/cfd/3");
	    doc.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
	    doc.setAttribute("xsi:schemaLocation", "http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd");
	}else{
	    doc.setAttribute("xmlns", "http://www.sat.gob.mx/cfd/2");
	    doc.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
	    doc.setAttribute("xsi:schemaLocation", "http://www.sat.gob.mx/cfd/2 http://www.sat.gob.mx/sitio_internet/cfd/2/cfdv22.xsd");
	    }
	  if (doc.getAttribute("fecha").isEmpty())
	  doc.setAttribute("fecha", dformat.format(Calendar.getInstance(TimeZone.getTimeZone("America/Mexico_City")).getTime()));
	  if (doc.getAttribute("tipoDeComprobante").isEmpty())
	  doc.setAttribute("tipoDeComprobante", "ingreso");
	//Metodo de Pago
	if (doc.getAttribute("metodoDePago")==null || doc.getAttribute("metodoDePago").isEmpty())
		doc.setAttribute("metodoDePago", "No identificado");
	  
	  NodeList lst = this.getNodes("Impuestos/Retenciones/Retencion");
	  Impuestos = (Element)doc.getElementsByTagName(domainPrefix + "Impuestos").item(0);
	  Double total=0.0;
	  if (Impuestos.getAttribute("totalImpuestosRetenidos").isEmpty() || Impuestos.getAttribute("totalImpuestosRetenidos")==null)
		  if (lst!=null)
			  for (int x=0;x<lst.getLength();x++){
				  Element e = (Element)lst.item(x);
				  total+= new Double(e.getAttribute("importe"));
			  }
	  if (total>0){
		  Impuestos.setAttribute("totalImpuestosRetenidos", numformat.format(total));
	  }
	  
	  lst = this.getNodes("Impuestos/Traslados/Traslado");
	  total=0.0;
	  if (Impuestos.getAttribute("totalImpuestosTrasladados").isEmpty() || Impuestos.getAttribute("totalImpuestosTrasladados")==null)
		  if (lst!=null)
			  for (int x=0;x<lst.getLength();x++){
				  Element e = (Element)lst.item(x);
				  total+= new Double(e.getAttribute("importe"));
			  }
	  if (total>0){
		    Impuestos.setAttribute("totalImpuestosTrasladados", numformat.format(total));
	  }
  }
  

  public void attachAddenda(String addenda){
	  Document doc = null;
	  Node element = null;
      //get the factory
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
      //Using factory get an instance of document builder
      DocumentBuilder db;
      Element addendaNode;
      ByteArrayInputStream ins = new ByteArrayInputStream(addenda.getBytes());
		try {
			db = dbf.newDocumentBuilder();
			doc = db.parse(ins);
			element = doc.removeChild(doc.getDocumentElement());
			  if (xmlDoc.getElementsByTagName(domainPrefix + "Addenda").getLength()>0)
				  addendaNode = (Element)xmlDoc.getElementsByTagName(domainPrefix + "Addenda").item(0);
			  else{
				  addendaNode = xmlDoc.createElement(domainPrefix + "Addenda");
				  doc.appendChild(addendaNode);
			  }
			xmlDoc.importNode(element, true);
			xmlDoc.adoptNode(element);
			addendaNode.appendChild(element);
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
  }

  public void attachAddenda(Document doc){
	  Node element = null;
	  Element addendaNode;
	  if (doc!=null && doc.getDocumentElement()!=null){
			element = doc.removeChild(doc.getDocumentElement());
			  if (xmlDoc.getElementsByTagName(domainPrefix + "Addenda").getLength()>0)
				  addendaNode = (Element)xmlDoc.getElementsByTagName(domainPrefix + "Addenda").item(0);
			  else{
				  addendaNode = xmlDoc.createElement(domainPrefix + "Addenda");
				  doc.appendChild(addendaNode);
			  }
			xmlDoc.importNode(element, true);
			xmlDoc.adoptNode(element);
			addendaNode.appendChild(element);
	  }
  }
  
  
  public String getLineaReporte(byte status){
	  
	//Only for version 2.x of CDF's
	if(!getAttrib(null,"version").startsWith("2"))
		return "";
    numformat.setMinimumFractionDigits(2);
    numformat.setMaximumFractionDigits(2);
    numformat.setGroupingUsed(false);
    
    String cadena = "|";
    Element Comprobante = xmlDoc.getDocumentElement();
    Element Receptor, Impuestos;


    Receptor = (Element)Comprobante.getElementsByTagName("Receptor").item(0);
    cadena += Receptor.getAttribute("rfc").isEmpty() ? "|" : Receptor.getAttribute("rfc") + "|";

    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss");
    Calendar cal = Calendar.getInstance();
        try {
            cal.setTime(df.parse(Comprobante.getAttribute("fecha")));
        } catch (ParseException ex) {
            Logger.getLogger(XmlFact.class.getName()).log(Level.SEVERE, null, ex);
        }
    //Deteccion del tipo de cambio 
    Double tc;
    if (Comprobante.getAttribute("TipoCambio")==null || Comprobante.getAttribute("TipoCambio").isEmpty())
    	tc=1d;
    else
    	tc = new Double(Comprobante.getAttribute("TipoCambio"));
    if (tc==0)
    	tc=1d;
    
    SimpleDateFormat dformat;
    dformat = (SimpleDateFormat)DateFormat.getDateInstance();
    dformat.applyPattern("dd/MM/yyyy' 'hh:mm:ss");
    cadena += Comprobante.getAttribute("serie").isEmpty() ? "|" : Comprobante.getAttribute("serie") + "|";
    cadena += Comprobante.getAttribute("folio").isEmpty() ? "|" : Comprobante.getAttribute("folio") + "|";
    cadena += Comprobante.getAttribute("anoAprobacion").isEmpty() ? "|" : Comprobante.getAttribute("anoAprobacion");
    cadena += Comprobante.getAttribute("noAprobacion").isEmpty() ? "|" : Comprobante.getAttribute("noAprobacion") + "|";
    cadena += dformat.format(cal.getTime()) + "|";
    cadena += Comprobante.getAttribute("total").isEmpty() ? "|" : numformat.format(new Double(Comprobante.getAttribute("total"))*tc) + "|";


    Impuestos = (Element)Comprobante.getElementsByTagName("Impuestos").item(0);
    cadena += Impuestos.getAttribute("totalImpuestosTrasladados").isEmpty() ? "|" : numformat.format(new Double(Impuestos.getAttribute("totalImpuestosTrasladados"))*tc) + "|";

    cadena += status + "|";
    if (!Comprobante.getAttribute("tipoDeComprobante").isEmpty()){
        char charTipo = Comprobante.getAttribute("tipoDeComprobante").charAt(0);
        cadena += Character.toUpperCase(charTipo) + "|";
    }
    cadena += "|||";
    return cadena.replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" +", " ").trim();  //Solo deja un espacio
  }
  
  /**
   * Agrega los nodos referentes al descuento al millar del .5%  facturas de obra pública
   * @param totalRetenciones
   * @param tasa
   * @param importe
   */
  public void addDescMillar(String totalRetenciones, String tasa, String importe){
	  Element complemento, impuestosLocales, retencionesLocales;
	  if (xmlDoc.getElementsByTagName(domainPrefix + "Complemento").getLength()>0)
		  complemento = (Element)xmlDoc.getElementsByTagName(domainPrefix + "Complemento").item(0);
	  else{
		  complemento = xmlDoc.createElement(domainPrefix + "Complemento");
		  doc.insertBefore(complemento,xmlDoc.getElementsByTagName(domainPrefix + "Addenda").item(0));
	  }
	  impuestosLocales = xmlDoc.createElement("implocal:ImpuestosLocales");
	  complemento.appendChild(impuestosLocales);

	  impuestosLocales.setAttribute("version", "1.0");
	  impuestosLocales.setAttribute("xmlns:implocal", "http://www.sat.gob.mx/implocal");
	  impuestosLocales.setAttribute("TotaldeRetenciones", totalRetenciones);
	  impuestosLocales.setAttribute("TotaldeTraslados", "0.00");

	  retencionesLocales = xmlDoc.createElement("implocal:RetencionesLocales");
	  impuestosLocales.appendChild(retencionesLocales);
	  
	  retencionesLocales.setAttribute("ImpLocRetenido", "MENOS .5% DE INSPECCION");
	  //se pone 0.5, ya que no acepta 0.005 (solo dos decimales)
	  DecimalFormat twoDForm = new DecimalFormat("############.##");
	  retencionesLocales.setAttribute("TasadeRetencion", twoDForm.format(new Double(tasa)*100));
	  retencionesLocales.setAttribute("Importe", importe);
  }
}
